/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */

#include "M2TextureLoader.h"

#include "OgreTexture.h"
#include "OgreImage.h"

#include "Logger.h"
#include "WOWUtil.h"
#include "WOWArchive.h"
#include "BLPFile.h"

#include "GEngine.h"
#include "GSpriteManager.h"

//using cximage now for image process
#include "ximage.h"

namespace GNgine
{
	M2TextureLoader::M2TextureLoader(M2File *m2File,M2TexType type)
		: _m2File(m2File),_modelInfo(0),_texType(type)
	{
		assert(_m2File);
	}

	M2TextureLoader::~M2TextureLoader()
	{
		if(_modelInfo){
			delete _modelInfo;
		}
	}

	void M2TextureLoader::loadResource(Ogre::Resource* resource)
	{
		assert(resource);

		_texture=static_cast<Ogre::Texture*>(resource);
		_texture->setUsage(Ogre::TU_DEFAULT);
		_texture->setTextureType(Ogre::TEX_TYPE_2D);
		_texture->setWidth(512);
		_texture->setHeight(512);
		_texture->setFormat(Ogre::PF_A8B8G8R8);

		_modelInfo=M2ModelInfo::get(_m2File);

		switch(_texType){
			case M2_TEX_TYPE_CHAR_BODY:
				initCharBodyTex();
				break;
			case M2_TEX_TYPE_CHAR_HAIR:
				initCharHairTex();
				break;
		}
		
	}

	void M2TextureLoader::initCharHairTex()
	{
		if(!_modelInfo->isCharacter()){
			return;
		}
		std::string path=_modelInfo->getHairTexturePath();
		BLPFile* blpFile=GNgWOWArchive.openBLPFile(path);
		if(!blpFile||blpFile->getWidth()==0||blpFile->getHeight()==0){
			return;
		}
		unsigned char* buf= blpFile->getMipmap(0);
		int width=blpFile->getWidth();
		int height=blpFile->getHeight();
		Ogre::DataStreamPtr stream=Ogre::DataStreamPtr(new Ogre::MemoryDataStream(buf,width*height*4));
		Ogre::Image image;
		image.loadRawData(stream,width,height,1,Ogre::PF_A8B8G8R8);
		
		Ogre::ConstImagePtrList imageList;
		imageList.push_back(&image);
		_texture->_loadImages(imageList);

		//GNgine.add2DSprite(Sprite2D::create(_texture,-1,1,-0.5,-0.5));
	}

	void M2TextureLoader::initCharBodyTex()
	{
		if(!_modelInfo->isCharacter()){
			return;
		}
		
		unsigned char* tempbuf=0;
		unsigned char* destbuf = (unsigned char*)malloc(REGION_PX*REGION_PX*4);
		int cnt=_modelInfo->getLayerCount();
		for (int i=0;i<cnt;i++) {
			CharTexLayer* layer=_modelInfo->getLayer(i);
			if(!layer){
				continue;
			}
			BLPFile* blpFile=GNgWOWArchive.openBLPFile(layer->fileName);
			if(!blpFile||blpFile->getWidth()==0||blpFile->getHeight()==0){
				continue;
			}
			int width=blpFile->getWidth();
			int height=blpFile->getHeight();
			tempbuf = (unsigned char*)malloc(width*height*4);

			memset(tempbuf, 0, width*height*4);
			

			CharTexCoord coord=charTexRegion[layer->region];
			if(width!=coord.xsize||height!=coord.ysize){
				memcpy(tempbuf,blpFile->getMipmap(0),width*height*4);//assume rgba
				
				CxImage *image=new CxImage(0);
				if(image){
					image->AlphaCreate();
					image->IncreaseBpp(32);
					image->CreateFromArray(tempbuf,width,height,32,(width*4),false);
					image->Resample(coord.xsize,coord.ysize,0);
					if(tempbuf!=0){
						delete tempbuf;
						tempbuf=0;
					}
					long size=coord.xsize*coord.ysize*4;
					image->Encode2RGBA(tempbuf,size,false);

					if(image!=0){
						delete image;
						image=0;
					}
				}
			}else{
				memcpy(tempbuf,blpFile->getMipmap(0),width*height*4);//assume rgba
			}
			
			for (int y=0, dy=coord.ypos; y<coord.ysize; y++,dy++) {
				for (int x=0, dx=coord.xpos; x<coord.xsize; x++,dx++) {
					unsigned char *src = tempbuf + y*coord.xsize*4 + x*4;
					unsigned char *dest = destbuf + dy*REGION_PX*4 + dx*4;
					float r = src[3] / 255.0f;
					float ir = 1.0f - r;
					dest[0] = (unsigned char)(dest[0]*ir + src[0]*r);
					dest[1] = (unsigned char)(dest[1]*ir + src[1]*r);
					dest[2] = (unsigned char)(dest[2]*ir + src[2]*r);
					dest[3] = 255;
				}
			}

			delete tempbuf;
		}

		Ogre::DataStreamPtr stream=Ogre::DataStreamPtr(new Ogre::MemoryDataStream(destbuf,REGION_PX*REGION_PX*4));
		Ogre::Image image;
		image.loadRawData(stream,REGION_PX,REGION_PX,1,Ogre::PF_A8B8G8R8);
		
		Ogre::ConstImagePtrList imageList;
		imageList.push_back(&image);
		_texture->_loadImages(imageList);
		
		delete destbuf;

		//test texture is load right?
		GNgEngine.add2DSprite(Sprite2D::create(_texture,-1,1,0,0));
	}
}
